﻿
//编译器类--把源程序编译为汇编程序
namespace n_ATMEGA_Assembler
{
using System;
using System.Text;

using n_ATMEGA_Label;
using n_Compiler;
using n_ConstString;
using n_ET;
using i_Compiler;
using n_OS;

public static class ATMEGA_Assembler
{
	static int ChipIndex;
	
	//编译器启动初始化,加载汇编运算库文件
	public static void LoadFile()
	{
		//加载运算信息表
		string s = i_Compiler.Compiler.OpenCompileFile( n_Config.Config.Path_compiler + "CPU" + OS.PATH_S + "ATMEGA" + OS.PATH_S + "hexcode.lst" );
		s = s.Remove( s.IndexOf( "\n<end>" ) );
		string[] Lines = s.Split( '\n' );
		HEXList = new string[ Lines.Length ][];
		for( int i = 0; i < Lines.Length; ++i ) {
			HEXList[ i ] = Lines[ i ].Remove( Lines[ i ].IndexOf( "<<<<" ) ).Split( '\\' );
		}
		//atmega16re标号初始化
		ATMEGA_Label.Init();
	}
	
	//编译汇编文件
	public static string Assemble( string Source, int ci )
	{
		ChipIndex = ci;
		
		n_Compiler.Compiler.CompilingStep( n_Compiler.Compiler.STEP_InitAssemble );
		
		//清除标号列表
		//ATMEGA_Label.Clear();
		Address = 0;
		
		n_Compiler.Compiler.CompilingStep( n_Compiler.Compiler.STEP_Assemble );
		
		//标准化,去除制表符等
		string[] Line = Standard( Source );
		
		//规范化, 去掉多余的空格
		Source = TrimMultSpace( Source );
		
		//转换为机器码
		Source = TurnToCode( Line );
		if( ET.isErrors() ) {
			return null;
		}
		//替换标号
		//Source = ATMEGA_Label.ReplaceLabel( Source );
		
		//计算表达式
		//Source = Express( Source );
		
		n_CodeData.CodeData.TotalByteNumber = Address * 2;
		n_CodeData.CodeData.isChanged = true;
		
		return Source.Trim( '\n' ) + "\n";
	}
	
	public static string ToHexCode( string Source )
	{
		//替换标号
		Source = ATMEGA_Label.ReplaceLabel( Source );
		
		//计算表达式
		Source = Express( Source );
		
		if( Source == null ) {
			return null;
		}
		return Source.Trim( '\n' ) + "\n";
	}
	
	//转换为机器码
	static string TurnToCode( string[] Line )
	{
		StringBuilder Result = new StringBuilder( "" );
		for( int i = 0; i < Line.Length; ++i ) {
			
			string line = Line[ i ];
			//去掉注释
			int noteIndex = line.IndexOf( "//" );
			if( noteIndex != -1 ) {
				line = line.Remove( noteIndex );
			}
			noteIndex = line.IndexOf( ";" );
			if( noteIndex != -1 ) {
				line = line.Remove( noteIndex );
			}
			line = line.Trim( ' ' );
			if( line == "" ) {
				continue;
			}
			//判断是否需要转换寻址指令
			//if( line.StartsWith( "ldd_" ) || line.StartsWith( "std_" ) ) {
			//	line = SwitchAccessIns( line );
			//}
			//提取数字,替换为 $n, n = 0,1,2,3 ...
			line = GetNumberChar( line );
			
			//获取机器码,包含表达式
			line = GetBINcode( line );
			
			if( line != null ) {
				Result.Append( line + "\n" );
			}
		}
		return Result.ToString();
	}
	
	//转换寻址指令
	static string SwitchAccessIns_TEMP( string line )
	{
		string[] ss = line.Split( ' ' );
		//string TypeTemp = null;
		//int Addr = int.Parse( ConstString.GetValue( ref TypeTemp, ss[ 3 ], 0 ) ) % 0x1000;
		switch( ss[ 0 ] ) {
			case "ldd_temp":	return "ldd " + ss[ 1 ] + " , " + "y+" + ss[ 3 ];
			case "ldd_local":	return "ldd " + ss[ 1 ] + " , " + "y+" + ss[ 3 ];
			case "ldd_static":	return "lds " + ss[ 1 ] + " , " + ss[ 3 ];
			case "std_temp":	return "std " + "y+" + ss[ 1 ] + " , " + ss[ 3 ];
			case "std_local":	return "std " + "y+" + ss[ 1 ] + " , " + ss[ 3 ];
			case "std_static":	return "sts " + ss[ 1 ] + " , " + ss[ 3 ];
			default: ET.ShowError( "系统错误: 未知的寻址方式: " + ss[ 0 ] ); return null;
		}
	}
	
	//规范化,去除制表符等
	static string[] Standard( string Source )
	{
		Source = Source.ToLower();
		Source = Source.Replace( ",", " , " );
		Source = Source.Replace( ":", " : " );
		Source = Source.Replace( '\t', ' ' );
		Source = Source.Replace( '\r', ' ' );
		Source = Source.Trim( "\n ".ToCharArray() );
		string[] Line = Source.Split( '\n' );
		return Line;
	}
	
	//计算源码中的表达式
	static string Express( string Source )
	{
		StringBuilder Result = new StringBuilder( ":020000020000FC\n" );
		StringBuilder lineHEX = new StringBuilder( "000000" );
		int ExpPC = 0;  //预期的PC值
		
		string[] line = Source.Split( '\n' );
		for( int i = 0; i < line.Length; ++i ) {
			
			CLine = i;
			
			string s = line[i];
			
			//转换为16位宽度机器码
			line[ i ] = SwitchToBIN( line[ i ] );
			if( line[ i ] == null ) {
				return null;
			}
			string[] Cut = line[ i ].Split( '\t' );
			string TypeTemp = null;
			int PC = int.Parse( ConstString.GetValue( ref TypeTemp, Cut[ 0 ], 0 ) );
			string BIN = Cut[ 1 ];
			if( BIN.IndexOf( "." ) != -1 ) {
				string[] c = BIN.Split( '.' );
				int Offset = int.Parse( c[ 1 ] );
				Offset = Offset - ( PC + 1 );
				
				if( c[ 0 ].Length == 10 ) {
					if( Offset > 63 || Offset < -64 ) {
						ET.WriteLineError( 0, 0, "转移A超出偏移范围: " + Offset );
						Offset = 0;
					}
					if( Offset < 0 ) {
						Offset = 127 + Offset + 1;
					}
					BIN = c[ 0 ].Replace( "!", ToBIN( 7, Offset ) );
				}
				else {
					if( Offset > 2047 || Offset < -2048 ) {
						ET.WriteLineError( 0, 0, "转移B超出偏移范围: " + Offset + " " + line[i] );
						Offset = 0;
					}
					if( Offset < 0 ) {
						Offset = 127 + Offset + 1;
					}
					BIN = c[ 0 ].Replace( "!", ToBIN( 12, Offset ) );
				}
			}
			//转换为十六进制码
			string HEX = ToHEX( BIN );
			PC *= 2;
			if( PC != ExpPC || lineHEX.Length > 30 || PC == 65536 || (PC == 65534 && HEX.Length == 8) ) {
				
				if( PC == 65534 && HEX.Length == 8 ) {
					lineHEX.Append( HEX.Remove( 4 ) );
					HEX = HEX.Remove( 0, 4 );
					PC = 65536;
				}
				string InitS = (( lineHEX.Length - 6 ) / 2).ToString( "X" ).PadLeft( 2, '0' ) + lineHEX;
				lineHEX = new StringBuilder( InitS );
				
				Result.Append( ":" + InitS + GetCheckSum( InitS ) + "\n" );
				
				int tPC = PC;
				if( tPC >= 65536 ) {
					tPC -= 65536;
				}
				lineHEX = new StringBuilder( tPC.ToString( "X" ).PadLeft( 4, '0' ) + "00" );
				
				if( PC == 65536 ) {
					Result.Append( ":020000040001F9\n" );
				}
			}
			lineHEX.Append( HEX );
			ExpPC = PC + HEX.Length / 2;
		}
		//处理剩余符号
		if( lineHEX.Length > 6 ) {
			string InitS = (( lineHEX.Length - 6 ) / 2).ToString( "X" ).PadLeft( 2, '0' ) + lineHEX;
			lineHEX = new StringBuilder( InitS );
			Result.Append( ":" + lineHEX + GetCheckSum( lineHEX.ToString() ) + "\n" );
			Result.Append( ":00000001FF\n" );
		}
		return Result.ToString();
	}
	
	//为一行HEX代码添加校验和
	static string GetCheckSum( string number )
	{
		int Sum = 0;
		for( int i = 0; i < number.Length; i += 2 ) {
			Sum += int.Parse( number.Substring( i, 2 ), System.Globalization.NumberStyles.HexNumber );
			Sum = Sum % 256;
		}
		Sum = 256 - Sum;
		if( Sum == 256 ) {
			Sum = 0;
		}
		return Sum.ToString( "X" ).PadLeft( 2, '0' );
	}
	
	//把二进制数序列转换为十六进制数序列
	static string ToHEX( string BIN )
	{
		string HEX = "";
		for( int i = 0; i < BIN.Length; i += 4 ) {
			string bin = BIN[ i ].ToString() + BIN[ i + 1 ] + BIN[ i + 2 ] + BIN[ i + 3 ];
			HEX = BINtoHEX( bin ) + HEX;
		}
		string result = "";
		for( int i = 0; i < HEX.Length - 1; i += 2 ) {
			result += HEX[ i + 1 ].ToString() + HEX[ i ];
		}
		return result;
	}
	
	//4位二进制数转换为1位十六进制数
	static string BINtoHEX( string bin )
	{
		switch( bin ) {
			case "0000": return "0";
			case "0001": return "1";
			case "0010": return "2";
			case "0011": return "3";
			case "0100": return "4";
			case "0101": return "5";
			case "0110": return "6";
			case "0111": return "7";
			case "1000": return "8";
			case "1001": return "9";
			case "1010": return "A";
			case "1011": return "B";
			case "1100": return "C";
			case "1101": return "D";
			case "1110": return "E";
			case "1111": return "F";
			default: ET.ShowError( "未知的二进制数: " + bin ); return "0";
		}
	}
	
	//计算内嵌表达式,转换为16位二进制机器码
	static string SwitchToBIN( string line )
	{
		if( line.EndsWith( ":" ) ) {
			return line;
		}
		Start:
		while( line.IndexOf( "(" ) != -1 || line.IndexOf( ")" ) != -1 ) {
			int PadIndex = -1;
			for( int i = 0; i < line.Length; ++i ) {
				if( line[ i ] == '(' ) {
					PadIndex = i;
				}
				if( line[ i ] == ')' ) {
					
					line = Expression( line, PadIndex, i );
					if( line == null ) {
						return null;
					}
					goto Start;
				}
			}
		}
		return line;
	}
	
	//求解内嵌表达式, Start和End是区间,包含括号
	static string Expression( string line, int StartIndex, int EndIndex )
	{
		if( StartIndex < 0 ) {
			ET.WriteLineError( 0, CLine, "缺少小括号: " + line );
			return null;
		}
		string Head = line.Remove( StartIndex );
		string End = line.Remove( 0, EndIndex + 1 );
		string Exp = line.Substring( StartIndex, EndIndex - StartIndex + 1 );
		Exp = Exp.Trim( "()".ToCharArray() );
		string Number1 = "";
		string Number2 = "";
		string Oper = "";
		bool isFirst = true;
		for( int i = 0; i < Exp.Length; ++i ) {
			if( Exp[ i ] == '+' || Exp[ i ] == '-' || Exp[ i ] == ':' ||
			    Exp[ i ] == '*' || Exp[ i ] == '/' || Exp[ i ] == '%' ) {
				isFirst = false;
				Oper = Exp[ i ].ToString();
				continue;
			}
			if( isFirst ) {
				Number1 += Exp[ i ];
			}
			else {
				Number2 += Exp[ i ];
			}
		}
		string Result = null;
		string Type = null;
		int N1 = int.Parse( ConstString.GetValue( ref Type, Number1, 0 ) );
		int N2 = int.Parse( ConstString.GetValue( ref Type, Number2, 0 ) );
		if( ET.isErrors() ) {
			ET.WriteLineError( 0, 0, "汇编过程出现错误, 内嵌表达式常量转换失败: " + line );
			return null;
		}
		switch( Oper ) {
			case "+": Result = ( N1 + N2 ).ToString(); break;
			case "-": Result = ( N1 - N2 ).ToString(); break;
			case "*": Result = ( N1 * N2 ).ToString(); break;
			case "/": Result = ( N1 / N2 ).ToString(); break;
			case "%": Result = ( N1 % N2 ).ToString(); break;
			case ":": Result = ToBIN( N1, N2 ); break;
			default:  ET.ShowError( "未知的运算: " + Oper ); break;
		}
		return Head + Result + End;
	}
	
	//把一个十进制数转换为某一长度的二进制数 N2 -> N1(宽度)
	static string ToBIN( int N1, int N2 )
	{
		string r = "";
		for( int i = 0; i < N1; ++i ) {
			r = N2 % 2 + r;
			N2 /= 2;
		}
		return r;
	}
	
	//查找机器码表,替换
	//格式:机器码(包含带小括号的表达式形式)
	//(4:?0+0x10) ...
	static string GetBINcode( string line )
	{
		if( line == null ) {
			return null;
		}
		if( line.StartsWith( ".db " ) ) {
			return line.Remove( 0, 4 );
		}
		string[] Cut = line.Split( '\\' );
		for( int i = 0; i < HEXList.Length; ++i ) {
			if( Cut[ 0 ] == HEXList[ i ][ 0 ] ) {
				string result = HEXList[ i ][ 1 ];
				for( int j = 1; j < Cut.Length; ++j ) {
					result = result.Replace( "?" + ( j - 1 ), Cut[ j ] );
				}
				string r = Address + "\t" + result;
				Address += int.Parse( HEXList[ i ][ 2 ] );
				return r;
			}
		}
		ET.WriteLineError( 0, 0, "汇编程序格式错误: " + line );
		return line;
	}
	
	//提取数字,替换为 $n, n = 0,1,2,3 ...
	//格式: 语句 + \ + 数字1 + \ + 数字2 + \ + ...
	//语句中对应的数字序列则替换为 ?n
	static string GetNumberChar( string line )
	{
		StringBuilder sentence = new StringBuilder( "" );
		StringBuilder NumberSet = new StringBuilder( "" );
		bool isFirstNumber = true;
		bool LastisNumber = false;
		int Index = 0;
		
		//判断标号
		if( line.EndsWith( ":" ) ) {
			string LabelName = line.Split( ' ' )[ 0 ];
			ATMEGA_Label.AddNode( LabelName, Address.ToString() );
			return null;
		}
		//判断地址定位指令
		if( line.StartsWith( ".org " ) ) {
			string Addr = line.Split( ' ' )[ 1 ];
			string type = null;
			Address = int.Parse( ConstString.GetValue( ref type, Addr, 0 ) );
			return null;
		}
		//判断数据定义
		if( line.StartsWith( ".db " ) ) {
			return SwitchData( line );
		}
		//如果含有标签,处理标签
		string label = "";
		int labelisExist = isLabelSentence( line );
		if( labelisExist == 1 ) {
			int i = line.LastIndexOf( ' ' );
			label = line.Remove( 0, i + 1 );
			line = line.Remove( i + 1 );
		}
		if( labelisExist == 2 ) {
			int i = line.LastIndexOf( ' ' );
			label = line.Remove( 0, i + 1 );
			line = line.Remove( i + 1 );
		}
		//处理数字序列
		int lineLength = line.Length;
		for( int i = 0; i < lineLength; ++i ) {
			if( LastisNumber &&
			    ( line[ i ] == 'b' || line[ i ] == 'x' || line[ i ] == 'a' || line[ i ] == 'b' ||
			    line[ i ] == 'c' || line[ i ] == 'd' || line[ i ] == 'e' || line[ i ] == 'f' ) ) {
				NumberSet.Append( line[ i ] );
				LastisNumber = true;
				continue;
			}
			if( line[ i ] < '0' || line[ i ] > '9' ) {
				sentence.Append( line[ i ] );
				isFirstNumber = true;
				LastisNumber = false;
				continue;
			}
			if( isFirstNumber ) {
				NumberSet.Append( "\\" );
				sentence.Append( "?" + Index );
				++Index;
				isFirstNumber = false;
			}
			NumberSet.Append( line[ i ] );
			LastisNumber = true;
		}
		if( labelisExist != 0 ) {
			sentence.Append( "?" + Index );
			NumberSet.Append( "\\" + label );
		}
		return sentence.Append( NumberSet ).ToString();
	}
	
	//处理数据定义
	static string SwitchData_old( string line )
	{
		string Result = ".db ";
		line = line.Remove( 0, 4 );
		string[] Word = line.Split( ',' );
		for( int i = 0; i < Word.Length; i += 2 ) {
			try {
				if( Word[i].Trim( ' ' ).StartsWith( "&" ) ) {
					string label_l = "_" + n_Config.Config.PreLabel.Function + Word[i].Trim( ' ' ).Remove( 0, 2 ) + "_";
					string label_h = "_" + n_Config.Config.PreLabel.Function + Word[i+1].Trim( ' ' ).Remove( 0, 2 ) + "_";
					Result += Address + "\t(8:(" + label_l + "/256))(8:(" + label_l + "%256))" + "\n";
				}
				else {
					Result += Address + "\t(8:" + Word[ i + 1 ].Trim( ' ' ) + ")(8:" + Word[ i ].Trim( ' ' ) + ")" + "\n";
				}
			}
			catch {
				ET.ShowError( "<SwitchData>" + line );
			}
			Address += 1;
		}
		return Result.Trim( '\n' );
	}
	
	//处理数据定义
	static string SwitchData( string line )
	{
		string Result = ".db ";
		line = line.Remove( 0, 4 );
		string[] Word = line.Split( ',' );
		for( int i = 0; i < Word.Length; i += 2 ) {
			try {
				if( Word[i].Trim( ' ' ).StartsWith( "&l" ) ) {
					string label_l = "_" + Word[i].Trim( ' ' ).Remove( 0, 2 ) + "_";
					string label_h = "_" + Word[i+1].Trim( ' ' ).Remove( 0, 2 ) + "_";
					Result += Address + "\t(8:(" + label_l + "/256))(8:(" + label_l + "%256))" + "\n";
				}
				else if( Word[i].Trim( ' ' ).StartsWith( "&e" ) ) {
					string label_l = "_" + Word[i].Trim( ' ' ).Remove( 0, 2 ) + "_";
					Result += Address + "\t(8:(" + label_l + "/65536))(8:0)" + "\n";
				}
				else {
					Result += Address + "\t(8:" + Word[ i + 1 ].Trim( ' ' ) + ")(8:" + Word[ i ].Trim( ' ' ) + ")" + "\n";
				}
			}
			catch {
				ET.ShowError( "<SwitchData>" + Word[i] + "  " + Word[i+1] + "\n" + line );
			}
			Address += 1;
		}
		return Result.Trim( '\n' );
	}
	
	//判断是否包含标签
	static int isLabelSentence( string line )
	{
		if( line.StartsWith( "load_ch " ) ||
		    line.StartsWith( "load_cl " ) ) {
			return 2;
		}
		if( line.StartsWith( "load_h " ) ||
		    line.StartsWith( "load_l " ) ||
		    line.StartsWith( "rjmp " ) ||
		    line.StartsWith( "jmp " ) ||
		    line.StartsWith( "rcall " ) ||
		    line.StartsWith( "call " ) ||
		    line.StartsWith( "brbs " ) ||
		    line.StartsWith( "brbc " ) ||
		    line.StartsWith( "breq " ) ||
		    line.StartsWith( "brne " ) ||
		    line.StartsWith( "brcs " ) ||
		    line.StartsWith( "brcc " ) ||
		    line.StartsWith( "brsh " ) ||
		    line.StartsWith( "brlo " ) ||
		    line.StartsWith( "brmi " ) ||
		    line.StartsWith( "brpl " ) ||
		    line.StartsWith( "brge " ) ||
		    line.StartsWith( "brlt " ) ||
		    line.StartsWith( "brhs " ) ||
		    line.StartsWith( "brhc " ) ||
		    line.StartsWith( "brts " ) ||
		    line.StartsWith( "brtc " ) ||
		    line.StartsWith( "brvs " ) ||
		    line.StartsWith( "brvc " ) ||
		    line.StartsWith( "brie " ) ||
		    line.StartsWith( "brid " ) ) {
			return 1;
		}
		return 0;
	}
	
	//去掉多余的空格
	static string TrimMultSpace( string line )
	{
		StringBuilder r = new StringBuilder( "" );
		bool ignore = true;
		for( int i = 0; i < line.Length; ++i ) {
			if( line[ i ] != ' ' ) {
				r.Append( line[ i ] );
				ignore = false;
				continue;
			}
			if( !ignore ) {
				r.Append( " " );
				ignore = true;
			}
		}
		return r.ToString();
	}
	
	static string[][] HEXList;
	public static int Address;
	static int CLine;
}
}

